package com.qwiki.text;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Corresponds to main text in wikipedia.
 * 
 * @author xgu
 * 
 * @since May 30, 2012
 */
public class TextNode extends Node
{
  List<Node> children;

  @Override
  public String getText()
  {
    if (!parsed)
      throw new IllegalStateException("not parsed yet");
    StringBuffer sb = new StringBuffer();
    for (Node n : getChildren())
    {
      String nodetext = n.getText();
      // if (n instanceof InternalLinkNode)
      // {
      // if (nodetext.equals(""))
      // nodetext = "null" + n.getOriginalText();
      // nodetext = "\nInternalLinkNode: " + nodetext + "\n";
      // }
      sb.append(nodetext);
    }
    return sb.toString();
  }

  public String getOriginalText()
  {
    if (!parsed)
      throw new IllegalStateException("not parsed yet");
    StringBuffer sb = new StringBuffer();
    for (Node n : getChildren())
    {
      if (n instanceof PlainText)
      {
        sb.append(n.getOriginalText());
      } else
      {
        sb.append("\n" + n.getClass().getSimpleName() + " " + n.getOriginalText() + "\n");
      }
    }
    return sb.toString();
  }

  @Override
  public List<Node> getChildren()
  {
    if (!parsed)
      throw new IllegalStateException("not parsed yet");
    return children;
  }

  @Override
  public boolean parse(char[] buffer, int start)
  {
    this.buffer = buffer;
    this.start = start;
    children = new ArrayList<Node>();
    int current = start;
    while (current < buffer.length)
    {
      boolean r = false;
      Node node = null;
      if (!r)
      {
        node = new NowikiNode(); // <nowiki>...</nowiki>
        r = node.parse(buffer, current);
      }
      if (!r)
      {
        node = new CommentNode(); // <!-- ...... -->
        r = node.parse(buffer, current);
      }
      if (!r)
      {
        node = new InternalLinkNode();// [[.....]]
        r = node.parse(buffer, current);
      }
      if (!r)
      {
        node = new ExternalLinkNode(); // [http://]
        r = node.parse(buffer, current);
      }
      if (!r)
      {
        node = new ReferenceNode(); // <ref.../></ref>
        r = node.parse(buffer, current);
      }
      if (!r)
      {
        node = new TableNode(); // \n{|....\n|}
        r = node.parse(buffer, current);
      }
      if (!r)
      {
        node = new TemplateNode(); // {{....}}
        r = node.parse(buffer, current);
      }
      if (!r)
      {
        node = new MathNode(); // <math>...</math>
        r = node.parse(buffer, current);
      }
      if (!r)
      {
        node = new TagXNode("gallery", true); // <gallery>...</gallery>
        r = node.parse(buffer, current);
      }
      if (!r)
      {
        current++;
      } else
      {
        current += node.getLength();
        if (node.start > start)
        {
          PlainText text = new PlainText();
          text.buffer = buffer;
          text.start = start;
          text.end = node.start;
          text.parsed = true;
          start = current;
          children.add(text);
          this.end = text.end;
        }
        children.add(node);
        this.end = node.end;
        start = current;
      }
    }
    if (this.end != buffer.length)
    {
      PlainText text = new PlainText();
      text.buffer = buffer;
      text.start = this.end;
      text.end = buffer.length;
      text.parsed = true;
      children.add(text);
      this.end = buffer.length;
    }
    parsed = true;
    return true;
  }

  public String[] getCategories()
  {
    if (!parsed)
      throw new IllegalStateException("not parsed yet");
    ArrayList<String> cats = new ArrayList<String>();
    for (Node n : getChildren())
    {
      if (n.isCategory() && n.getCategory() != null && n.getCategory().length() > 0 && !cats.contains(n.getCategory()))
      {
        cats.add(n.getCategory());
      }
      // if (n instanceof InternalLinkNode)
      // {
      // if (nodetext.equals(""))
      // nodetext = "null" + n.getOriginalText();
      // nodetext = "\nInternalLinkNode: " + nodetext + "\n";
      // }
    }
    return cats.toArray(new String[0]);
  }

  /**
   * @return the names of the entities of internal links.
   */
  public String[] getEntities()
  {
    if (!parsed)
      throw new IllegalStateException("not parsed yet");
    ArrayList<String> links = new ArrayList<String>();
    for (Node n : getChildren())
    {
      if (n instanceof InternalLinkNode)
      {
        InternalLinkNode link = (InternalLinkNode) n;
        String linktext = link.getEntity();
        if (linktext.length()>0 && !links.contains(linktext))
        {
          links.add(linktext);
        }
      }
    }
    return links.toArray(new String[0]);
  }

  public String[] getCategoryMore(String categoryTitle)
  {
    if (!parsed)
      throw new IllegalStateException("not parsed yet");
    ArrayList<String> more = new ArrayList<String>();
    for (Node n : getChildren())
    {
      String template = n.getOriginalText();
      boolean good = template != null && (template.startsWith("{{Cat main") || template.startsWith("{{Cat more"));
      if (n instanceof TemplateNode && good)
      {
        int bar = template.indexOf('|');
        if (bar < 0 && !more.contains(categoryTitle))
        {
          more.add(categoryTitle);
        } else
        {
          template = template.substring(bar + 1, template.length() - 2);
          if (!more.contains(template))
            more.add(template);
        }
      }
    }
    return more.toArray(new String[0]);
  }
}
